package com.yuno.mock.strategy.impl;

import com.yuno.mock.dto.ExcelReadRequest;
import com.yuno.mock.strategy.ShardingStrategy;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 基于行的分片策略实现
 * 
 * @author xrm
 * @since 1.0.0
 */
@Component
public class RowBasedShardingStrategy implements ShardingStrategy {
    
    private static final String STRATEGY_NAME = "ROW_BASED";
    
    @Override
    public List<Shard> createShards(ExcelReadRequest request, long totalRows) {
        List<Shard> shards = new ArrayList<>();
        
        // 获取配置参数
        int minRowsPerShard = request.getMinRowsPerShard();
        int maxRowsPerShard = request.getMaxRowsPerShard();
        int maxShards = request.getMaxShards();
        
        // 计算实际需要的分片数
        long actualRows = calculateActualRows(request, totalRows);
        int optimalShards = calculateOptimalShards(actualRows, minRowsPerShard, maxRowsPerShard, maxShards);
        
        // 计算每个分片的行数
        long rowsPerShard = actualRows / optimalShards;
        long remainingRows = actualRows % optimalShards;
        
        long currentStartRow = request.getStartRow();
        long actualEndRow = request.getEndRow() == -1 ? totalRows : Math.min(request.getEndRow(), totalRows);
        
        for (int i = 0; i < optimalShards; i++) {
            long shardSize = rowsPerShard;
            // 将余数分配给前面的分片
            if (i < remainingRows) {
                shardSize++;
            }
            
            long shardEndRow = currentStartRow + shardSize - 1;
            // 确保最后一个分片不超过实际结束行
            if (i == optimalShards - 1) {
                shardEndRow = actualEndRow;
            }
            
            String shardId = generateShardId(i);
            Shard shard = new Shard(shardId, currentStartRow, shardEndRow, 
                    request.getSheetName(), request.getSheetIndex());
            
            // 设置优先级（较小的分片优先级更高）
            shard.setPriority(i);
            
            // 估算处理时间（基于行数和复杂度）
            long estimatedTime = estimateProcessingTime(shardSize, request);
            shard.setEstimatedTimeMs(estimatedTime);
            
            shards.add(shard);
            currentStartRow = shardEndRow + 1;
            
            // 防止超出范围
            if (currentStartRow > actualEndRow) {
                break;
            }
        }
        
        return shards;
    }
    
    @Override
    public String getStrategyName() {
        return STRATEGY_NAME;
    }
    
    @Override
    public boolean supports(String strategyName) {
        return STRATEGY_NAME.equals(strategyName);
    }
    
    /**
     * 计算实际需要处理的行数
     */
    private long calculateActualRows(ExcelReadRequest request, long totalRows) {
        long startRow = request.getStartRow();
        long endRow = request.getEndRow() == -1 ? totalRows : Math.min(request.getEndRow(), totalRows);
        return Math.max(0, endRow - startRow + 1);
    }
    
    /**
     * 计算最优分片数
     */
    private int calculateOptimalShards(long actualRows, int minRowsPerShard, int maxRowsPerShard, int maxShards) {
        if (actualRows <= minRowsPerShard) {
            return 1;
        }
        
        // 基于最大行数计算最小分片数
        int minShardsNeeded = (int) Math.ceil((double) actualRows / maxRowsPerShard);
        
        // 基于最小行数计算最大分片数
        int maxShardsAllowed = (int) (actualRows / minRowsPerShard);
        
        // 取合理范围内的值
        int optimalShards = Math.min(maxShardsAllowed, maxShards);
        optimalShards = Math.max(optimalShards, minShardsNeeded);
        
        return Math.max(1, optimalShards);
    }
    
    /**
     * 生成分片ID
     */
    private String generateShardId(int shardIndex) {
        return String.format("ROW_SHARD_%03d_%s", shardIndex, 
                UUID.randomUUID().toString().substring(0, 8));
    }
    
    /**
     * 估算处理时间
     */
    private long estimateProcessingTime(long rowCount, ExcelReadRequest request) {
        // 基础处理时间：每行5毫秒
        long baseTime = rowCount * 5;
        
        // 根据列数调整（更多列需要更多时间）
        int columnCount = calculateColumnCount(request);
        double columnFactor = 1.0 + (columnCount - 1) * 0.1; // 每增加一列增加10%时间
        
        // 根据数据类型复杂度调整
        double complexityFactor = 1.0;
        if (request.getDataTypes() != null && !request.getDataTypes().isEmpty()) {
            complexityFactor = 1.2; // 有数据类型转换增加20%时间
        }
        
        // 根据是否跳过空行/列调整
        double skipFactor = 1.0;
        if (request.getSkipEmptyRows() || request.getSkipEmptyColumns()) {
            skipFactor = 1.1; // 跳过空行/列增加10%时间
        }
        
        return (long) (baseTime * columnFactor * complexityFactor * skipFactor);
    }
    
    /**
     * 计算列数
     */
    private int calculateColumnCount(ExcelReadRequest request) {
        if (request.getEndColumn() == -1) {
            return 10; // 默认假设10列
        }
        return Math.max(1, request.getEndColumn() - request.getStartColumn() + 1);
    }
}